package edu.hawaii.jmotif.sequitur.model;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Observable;
import org.hackystat.utilities.stacktrace.StackTrace;
import edu.hawaii.jmotif.sequitur.logic.MotifChartData;
import edu.hawaii.jmotif.timeseries.Timeseries;

public class SequiturModel extends Observable {

  private String dataFileName;
  private double[] ts;
  private MotifChartData chartData;

  public void setDataFileName(String filename){
	  dataFileName = filename;
  }
  
  public synchronized String getCurrentDataFile() {
    return this.dataFileName;
  }

  public void setCurrentDataFile(String absolutePath) {
    this.dataFileName = absolutePath;
    this.setChanged();
    notifyObservers(new SequiturMessage(SequiturMessage.DATA_FNAME, this.dataFileName));
    this.setChanged();
    notifyObservers(new SequiturMessage(SequiturMessage.STATUS_MESSAGE, "model: selected "
        + this.dataFileName + " as data source"));
  }

  /**
   * Load the data which is supposedly in the file which is selected as the data source.
   * 
   * @param limitStr the limit of lines to read.
   */
  public void loadData(String limitStr) {

    if ((null == this.dataFileName) || this.dataFileName.isEmpty()) {
      setChanged();
      notifyObservers(new SequiturMessage(SequiturMessage.STATUS_MESSAGE,
          "model: no data source selected yet."));
      return;
    }

    File f = new File(this.dataFileName);
    if (!(f.exists())) {
      setChanged();
      notifyObservers(new SequiturMessage(SequiturMessage.STATUS_MESSAGE, "model: source "
          + this.dataFileName + " doesnt exist."));
      return;
    }

    ArrayList<Double> data = new ArrayList<Double>();

    BufferedReader reader;
    try {

      long loadLimit = 0l;

      if (!(null == limitStr) && !(limitStr.isEmpty())) {
        loadLimit = Long.valueOf(limitStr);
      }

      reader = new BufferedReader(new FileReader(f));

      String line = null;
      long lineCounter = 0;
      while ((line = reader.readLine()) != null) {
        line = line.replace(',', '.'); // ??? Locale
        double value = Double.parseDouble(line);
        data.add(value);
        lineCounter++;
        if ((loadLimit > 0) && (lineCounter >= loadLimit)) {
          break;
        }
      }
      reader.close();
    }
    catch (Exception e) {
      System.err.println(StackTrace.toString(e));
      setChanged();
      notifyObservers(new SequiturMessage(SequiturMessage.STATUS_MESSAGE,
          "model: error while trying to read the data from " + this.dataFileName));
    }
    finally {
      assert true;
    }

    if (!(data.isEmpty())) {
      this.ts = new double[data.size()];
      for (int i = 0; i < data.size(); i++) {
        this.ts[i] = data.get(i);
      }
    }

    setChanged();
    notifyObservers(new SequiturMessage(SequiturMessage.STATUS_MESSAGE, "model: loaded "
        + data.size() + " points"));

  }

  public void processData(int windowSize, int paaSize, int alphabetSize) {
    this.chartData = new MotifChartData(new Timeseries(this.ts), windowSize, alphabetSize, paaSize);
    this.chartData.buildSAX();
    setChanged();
    notifyObservers(new SequiturMessage(SequiturMessage.STATUS_MESSAGE, "model: processed data."));
  }

  public void displayStuff() {
    setChanged();
    notifyObservers(new SequiturMessage(SequiturMessage.STATUS_MESSAGE,
        "model: broadcasting the Sequitur data."));
    setChanged();
    notifyObservers(new SequiturMessage(SequiturMessage.CHART_MESSAGE, this.chartData));
  }

}
